using Engine;
using Engine.Graphics;
using Engine.Graphics.RenderableObjects;
using Engine.TrafficHelpers;
using ModelViewer.GraphicObjects;
using ModelViewer.Windows;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace ModelViewerTabs.TabsForModelviewer
{
    public partial class StreetNodeTab : UserControl, IRenderableObject
    {
        #region Private Fields

        private List<CrossroadTraffic> crossroadTraffic;
        private Engine.Engine engine;
        private List<NodeMesh> nodesPosition;
        private List<NodeMesh> nodesTangents;
        private TrafficCrossroadMesh trafficCrossroadMesh;
        private bool updatingControls = false;

        #endregion Private Fields

        #region Public Constructors

        public StreetNodeTab()
        {
            InitializeComponent();
            this.crossroadTraffic = new List<CrossroadTraffic>();
            this.nodesPosition = new List<NodeMesh>();
            this.nodesTangents = new List<NodeMesh>();

            // Add tooltip Infos
            this.toolTipInfos.SetToolTip(this.checkBox_GetPositionAndAngle, "After you pressed this checkbox, you can click on a polygon of the\n" +
                " 3d mesh in the viewport to set the position of the selected node.");
        }

        #endregion Public Constructors

        #region Public Properties

        public Engine.Engine Engine
        {
            set
            {
                engine = value;
                this.trafficCrossroadMesh = new TrafficCrossroadMesh(this.engine);
                this.engine.Grafic.AddRenderableObjects(this, 1000);
            }
        }

        #endregion Public Properties

        #region Public Methods

        public void ClearList()
        {
            for (int i = 0; i < this.crossroadTraffic.Count; i++)
            {
                this.nodesPosition[i].Dispose();
                this.nodesTangents[i].Dispose();
            }
            this.nodesPosition.Clear();
            this.nodesTangents.Clear();
            this.crossroadTraffic.Clear();
            this.listBox_Streetnodes.Items.Clear();
        }

        void IRenderableObject.Dispose()
        {
            for (int i = 0; i < this.nodesTangents.Count; i++)
            {
                this.nodesTangents[i].Dispose();
            }
            for (int i = 0; i < this.nodesPosition.Count; i++)
            {
                this.nodesPosition[i].Dispose();
            }
            this.trafficCrossroadMesh.Dispose();
            this.engine.Grafic.RemoveRenderableObject(this);
        }

        void IRenderableObject.Render(int renderStep)
        {
            this.engine.Grafic.DepthStateEnableZ(false);

            for (int i = 0; i < this.crossroadTraffic.Count; i++)
            {
                this.nodesPosition[i].Draw();
                this.nodesTangents[i].Draw();
            }
            this.trafficCrossroadMesh.Render(0);
        }

        public void SetNodePosition(Vector3 position, decimal angle)
        {
            this.numericUpDown_PositionX.Value = (decimal)position.X;
            this.numericUpDown_PositionY.Value = (decimal)position.Y;
            this.numericUpDown_PositionZ.Value = (decimal)position.Z;
            this.numericUpDown_Rotation.Value = angle % 360;
        }

        public void SetStreetNodes(List<CrossroadTraffic> crossroadTraffic)
        {
            ClearList();

            for (int i = 0; i < crossroadTraffic.Count; i++)
                AddNewStreetNode(crossroadTraffic[i], crossroadTraffic[i].StreetNode.Position);
        }

        #endregion Public Methods

        #region Internal Methods

        internal List<CrossroadTraffic> GetCrossroadTraffic()
        {
            return this.crossroadTraffic;
        }

        #endregion Internal Methods

        #region Private Methods

        private void AddNewStreetNode(CrossroadTraffic crossroadTraffic, Vector3 position)
        {
            this.crossroadTraffic.Add(crossroadTraffic);
            this.listBox_Streetnodes.Items.Add(crossroadTraffic);
            this.nodesPosition.Add(new NodeMesh(this.engine, crossroadTraffic.StreetNode.Position, System.Drawing.Color.Red));
            this.nodesTangents.Add(new NodeMesh(this.engine, crossroadTraffic.StreetNode.GetPositionFromTangent(crossroadTraffic.LaneForward.TangentLengthStart) + crossroadTraffic.StreetNode.Position, System.Drawing.Color.Blue));
            this.trafficCrossroadMesh.UpdateTraffic(this.crossroadTraffic.ToArray(), Vector3.Zero);
        }

        private void button_AddnewStreetnod_Click(object sender, EventArgs e)
        {
            int index = this.listBox_Streetnodes.Items.Count;
            float x = (float)this.numericUpDown_PositionX.Value;
            float y = (float)this.numericUpDown_PositionY.Value;
            float z = (float)this.numericUpDown_PositionZ.Value;
            double angle = (float)this.numericUpDown_Rotation.Value;
            Vector2 rotation = GeoMath.GetVectorFromAngle(angle);
            CrossroadTraffic crossroadTraffic = crossroadTrafficControl.GetCrossroadTraffic();
            AddNewStreetNode(crossroadTraffic, new Vector3(x, y, z));
        }

        private void button_RemoveSelectedStreetnode_Click(object sender, EventArgs e)
        {
            ListBox.SelectedIndexCollection collection = this.listBox_Streetnodes.SelectedIndices;
            for (int i = collection.Count - 1; i >= 0; i--)
            {
                RemoveStreetNode(collection[i]);
            }
        }

        private void button_Rename_Click(object sender, EventArgs e)
        {
            if (this.listBox_Streetnodes.SelectedIndex > -1)
            {
                CrossroadTraffic streetnode = (CrossroadTraffic)this.listBox_Streetnodes.SelectedItem;
                RenameWindow renameWindow = new RenameWindow();
                renameWindow.Text = streetnode.Name;
                if (renameWindow.ShowDialog() == DialogResult.OK)
                {
                    streetnode.Name = renameWindow.Text; // string.Format("Hallo {0}", this.listBox_Streetnodes.SelectedIndex);
                    this.listBox_Streetnodes.Items[this.listBox_Streetnodes.SelectedIndex] = streetnode;
                    this.crossroadTraffic[this.listBox_Streetnodes.SelectedIndex] = streetnode;
                }
            }
        }

        private void listBox_Streetnodes_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.listBox_Streetnodes.SelectedItems.Count == 1)
            {
                this.updatingControls = true;
                int index = this.listBox_Streetnodes.SelectedIndex;

                this.numericUpDown_PositionX.Value = (decimal)this.crossroadTraffic[index].StreetNode.positionX;
                this.numericUpDown_PositionY.Value = (decimal)this.crossroadTraffic[index].StreetNode.positionY;
                this.numericUpDown_PositionZ.Value = (decimal)this.crossroadTraffic[index].StreetNode.positionZ;
                this.numericUpDown_Rotation.Value = (decimal)this.crossroadTraffic[index].StreetNode.GetDirectionInDegree();
                this.crossroadTrafficControl.SetCrossroadTraffic(this.crossroadTraffic[index]);

                this.updatingControls = false;
            }
        }

        private void OnValueChange(object sender, EventArgs e)
        {
            if (this.numericUpDown_Rotation.Value < 0)
                this.numericUpDown_Rotation.Value += 360;
            if (this.numericUpDown_Rotation.Value >= 360)
                this.numericUpDown_Rotation.Value -= 360;

            if (!this.updatingControls)
            {
                ListBox.SelectedIndexCollection collection = this.listBox_Streetnodes.SelectedIndices;
                for (int i = collection.Count - 1; i >= 0; i--)
                {
                    int index = collection[i];
                    CrossroadTraffic crossroadTraffic = this.crossroadTraffic[index];
                    Vector3 position = new Vector3((float)this.numericUpDown_PositionX.Value,
                        (float)this.numericUpDown_PositionY.Value,
                        (float)this.numericUpDown_PositionZ.Value);
                    crossroadTraffic = this.crossroadTrafficControl.GetCrossroadTraffic();
                    double angle = (float)this.numericUpDown_Rotation.Value;
                    crossroadTraffic.SetStreetnodeProperties(position, angle);
                    this.crossroadTraffic[index] = crossroadTraffic;
                    this.nodesPosition[index].UpdatePosition(position);
                    this.nodesTangents[index].UpdatePosition(position + this.crossroadTraffic[index].StreetNode.GetPositionFromTangent(this.crossroadTraffic[index].LaneForward.TangentLengthStart));
                }

                this.trafficCrossroadMesh.UpdateTraffic(this.crossroadTraffic.ToArray(), Vector3.Zero);
            }
        }

        private void RemoveStreetNode(int index)
        {
            this.crossroadTraffic.RemoveAt(index);
            this.listBox_Streetnodes.Items.RemoveAt(index);
            this.nodesPosition[index].Dispose();
            this.nodesPosition.RemoveAt(index);
            this.nodesTangents[index].Dispose();
            this.nodesTangents.RemoveAt(index);

            this.trafficCrossroadMesh.UpdateTraffic(this.crossroadTraffic.ToArray(), Vector3.Zero);
        }

        private void SelectTextOnEnter(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(NumericUpDown))
            {
                NumericUpDown numericUpDown = sender as NumericUpDown;
                numericUpDown.Select(0, numericUpDown.ToString().Length);
            }
        }

        #endregion Private Methods
    }
}